﻿#include "../include/header/cat-config.hpp"

#include "../include/util/platform.hpp"
#include "../include/util/cmem.hpp"
#include "../include/util/darray.hpp"
#include "../include/util/base.hpp"
#include "../include/util/json.h"

#include "../include/cat-internal.hpp"
#include "../include/cat-audio.hpp"
#include "../include/cat-source.hpp"
#include "../include/cat-module.hpp"
#include "../include/cat-window.hpp"
#include "../include/cat-proc.hpp"
#include "../include/cat-signal.hpp"
#include "../include/cat-def.hpp"
#include "../include/cat-hook.hpp"
#include "../include/cat.hpp"

static struct cat_core* cat = NULL;

/*********************核心初始化或释放****************************/

const char* cat_get_version_string()
{
    return CAT_CORE_VERSION;
}

static bool cat_init(const char* module_config_path,char* default_config) {

    cat = (cat_core*)bzalloc(sizeof(struct cat_core));

    if (module_config_path)
        cat->module_config_path = bstrdup(module_config_path);
    if (default_config) {
        cat->default_config = cat_data_create_from_json(default_config);
        if (!cat->default_config) {
            blog(LOG_ERROR, "default config has error, fail to init");
            goto error;
        }
        cat->buffer_config = cat_data_create_from_json(default_config);
    }
    else
    {
        blog(LOG_ERROR, "default config not exist, fail to init");
        goto error;
    }

    cat->window = cat_creat_window();

    cat->cat_proc = cat_window_onproc;
    cat->cat_signal = on_signal;

    cat->buffer_config_mutex = new std::mutex();

    return true;

error:
    return false;
}

bool cat_startup(const char* config_path, const char* default_config)
{
    bool success;
    if (cat) {
        blog(LOG_WARNING, "Tried to call cat_startup more than once");
        return false;
    }
    success = cat_init(config_path,(char *)default_config);
    if (!success) {
        cat_shutdown();
        return success;
    }
    update_config();

    cat_hook_start(0);

    cat_ticktock_start();

    cat_audio_play_thread_start();
    return success;
}

void cat_shutdown(void)
{
    cat_module* module;
    cat_core* core;

    if (!cat)
        return;

    cat_hook_stop();

    cat_ticktock_stop();

    cat_audio_play_thread_stop();

    da_free(cat->module_paths);

    da_free(cat->mode_types);
    da_free(cat->input_types);
    da_free(cat->output_types);
    da_free(cat->ui_types);

    cat_source* source = cat->data.first_input;
    while (source)
    {
        cat_source* next = source->next;
        bfree(source);
        source = next;
    }
    cat_source* msource = cat->data.first_mode;
    while (msource)
    {
        cat_source* next = msource->next;
        bfree(msource);
        msource = next;
    }
    cat_source* osource = cat->data.first_output;
    while (osource)
    {
        cat_source* next = osource->next;
        bfree(osource);
        osource = next;
    }
    cat_source* usource = cat->data.first_ui;
    while (usource)
    {
        cat_source* next = usource->next;
        bfree(usource);
        usource = next;
    }

    core = cat;
    cat = NULL;

    delete core->buffer_config_mutex;
    core->buffer_config_mutex = NULL;

    module = core->first_module;
    while (module) {
        cat_module* next = module->next;
        free_module(module);
        module = next;
    }
    core->first_module = NULL;
    core->cat_proc = NULL;
    core->cat_signal = NULL;  

    cat_release_window(core->window);
    cat_data_release(core->default_config);
    cat_data_release(core->buffer_config);
    bfree(core->module_config_path);
    bfree(core);
}

bool cat_initailized(void)
{
    return cat!=NULL;
}

void cat_set_on_init(void(*cat_on_init)())
{
    if (cat) {
        cat->cat_on_init = cat_on_init;
    }
}

void cat_set_draw_func(void(*cat_draw)())
{
    if (cat) {
        cat->cat_draw = cat_draw;
    }
}
/*************************配置文件*************************************/

cat_data_t* cat_load_default_config() {
    cat_data_t* config = NULL;

    if (cat) {
        config = cat->default_config;

        config->json["main_decoration"]["window_handle"] = (long)cat_get_handle();
 
    }
    
    return config;
}

bool cat_save_default_config()
{
    if (!cat)
        return false;

    return cat_data_write_json_file(cat->default_config, cat_get_default_config_path());
}

const char* cat_get_default_config_path()
{
    if (cat)
        return cat->module_config_path;
    return NULL;
}

void update_config() {

    if (cat && cat->default_config&& cat->module_config_path) {
        cat_data_t* cfg = cat_data_create_from_json_file(cat->module_config_path);
        if (cfg)
        {
            int WIDTH, HEIGHT;
            WIDTH = cat->default_config->json["main_decoration"]["window_size"][0].asInt();
            HEIGHT = cat->default_config->json["main_decoration"]["window_size"][1].asInt();
            
            cat_data_update(*cat->default_config, *cfg);   

            cat->default_config->json["main_decoration"]["window_size"][0] = WIDTH;
            cat->default_config->json["main_decoration"]["window_size"][1] = HEIGHT;

            cat_data_release(cfg);
        } 
    }
}

void update_config_from_config_file(const char* path)
{
    cat_data_t* f_config = cat_data_create_from_json_file(cat_get_default_config_path());

    if (f_config) { 
        int WIDTH, HEIGHT;
        WIDTH = cat->default_config->json["main_decoration"]["window_size"][0].asInt();
        HEIGHT = cat->default_config->json["main_decoration"]["window_size"][1].asInt();

        cat_data_update(*cat->default_config, *f_config);

        cat->default_config->json["main_decoration"]["window_size"][0] = WIDTH;
        cat->default_config->json["main_decoration"]["window_size"][1] = HEIGHT;

        cat_data_release(f_config);
    }
}

cat_data_t* cat_get_buffer_config()
{
    if (!cat)
        return NULL; 

    return cat->buffer_config;
}

void update_config_from_buffer_config()
{
    if (cat && cat->default_config && cat->buffer_config) { 
       cat->buffer_config_mutex->lock();

       int WIDTH, HEIGHT;
       WIDTH = cat->default_config->json["main_decoration"]["window_size"][0].asInt();
       HEIGHT = cat->default_config->json["main_decoration"]["window_size"][1].asInt();

       cat_data_update(*cat->default_config, *cat->buffer_config);

       cat->default_config->json["main_decoration"]["window_size"][0] = WIDTH;
       cat->default_config->json["main_decoration"]["window_size"][1] = HEIGHT;  

       cat->buffer_config_mutex->unlock();
    }
}

void update_buffer_config_from_config()
{
    if (cat && cat->default_config && cat->buffer_config) {
        int WIDTH, HEIGHT;
        WIDTH = cat->default_config->json["main_decoration"]["window_size"][0].asInt();
        HEIGHT = cat->default_config->json["main_decoration"]["window_size"][1].asInt();

        cat_data_update(*cat->buffer_config, *cat->default_config);

        cat->default_config->json["main_decoration"]["window_size"][0] = WIDTH;
        cat->default_config->json["main_decoration"]["window_size"][1] = HEIGHT;
    }
}

void update_buffer_config_from_data(cat_data_t* newData)
{
    if (cat && cat->buffer_config) { 
        cat->buffer_config_mutex->lock();

        cat_data_t* buffer = cat_get_buffer_config();
        cat_data_update(*buffer, *newData);

        cat->buffer_config_mutex->unlock();
    }
}

bool cat_set_cat_font(const char* fontpath)
{
    bool success = false;
    if (cat && cat->window->catfont) {
        success = cat_set_font(cat->window,fontpath);
    }
    return success;
}

/*************************图形****************************************/


bool cat_open_gui(const char* title, const char* icon)
{
    bool success = false;

    success = cat_open_window(cat->window, title,icon);
    
    if(cat&&cat->cat_on_init)
        cat->cat_on_init();  

    return success;
}

bool cat_display_gui()
{
    bool ret = false;
    if (cat) {     
        if (cat->cat_signal)
            cat->cat_signal(cat->window);

        ret = cat->window->window->isOpen();

        if (ret&&cat->cat_proc)
            cat->cat_proc(cat->window);
    }
    return ret;
}

void cat_shatdown_gui()
{
    if (cat) {
        cat->window->window->close();
    }
}

void  cat_draw_cat()
{
      cat_clear_window(cat->window);

      cat->cat_draw();

      cat_display_window(cat->window);
}

void cat_close_gui()
{
    if (cat) {
        cat_push_signal(UIWM_WINDOWSHOULDCLOSE);
    }
}

void cat_set_gui_visible(bool _flag)
{
    if (cat && cat->window) {        
        _flag ? cat->window->window->setVisible(true) : cat->window->window->setVisible(false);
    }
}

void cat_set_gui_size(int width, int height)
{
    if (cat) {
        sf::FloatRect visibleArea(0, 0, width, height);
        cat->window->window->setView(sf::View(visibleArea));
    }
}

void* cat_get_handle()
{
    if (cat)
        return cat_get_window_handle(cat->window);
    return NULL;
}
void* cat_get_buffer_window_handle()
{
    if (cat)
        return (void*)cat_get_buffer_config()->json["main_decoration"]["window_handle"].asInt64();
    return NULL;
}

/*************************模块****************************************/

static inline int load_module_exports(cat_module_t* mod, const char* path);

int cat_open_module(cat_module_t** module, const char* path, const char* data_path)
{
    struct cat_module mod = { 0 };
    int errorcode;

    if (!module || !path || !cat)
        return MODULE_ERROR;

    blog(LOG_DEBUG, "---------------------------------");

    mod.module = cat_dlopen(path);
    if (!mod.module) {
        blog(LOG_WARNING, "Module '%s' not loaded", path);
        return MODULE_FILE_NOT_FOUND;
    }

    errorcode = load_module_exports(&mod, path);
    if (errorcode != MODULE_SUCCESS)
        return errorcode;

    mod.bin_path = bstrdup(path);
    mod.file = strrchr(mod.bin_path, '/');
    mod.file = (!mod.file) ? mod.bin_path : (mod.file + 1);
    mod.mod_name = bstrdup(mod.file);
    mod.data_path = bstrdup(data_path);
    mod.next = cat->first_module;

    if (mod.file) {
        blog(LOG_DEBUG, "Loading module: %s", mod.file);
    }

    *module = (cat_module_t*)bmemdup(&mod, sizeof(mod));
    cat->first_module = (*module);
    mod.set_pointer(*module);

    return MODULE_SUCCESS;
}

static inline int req_func_not_found(const char* name, const char* path)
{
    blog(LOG_DEBUG,
        "Required module function '%s' in module '%s' not "
        "found, loading of module failed",
        name, path);
    return MODULE_MISSING_EXPORTS;
}

int load_module_exports(cat_module_t* mod, const char* path)
{
    mod->load = (bool(*)())cat_dlsym(mod->module, "cat_module_load");
    if (!mod->load)
        return req_func_not_found("cat_module_load", path);

    mod->set_pointer = (void (*)(cat_module_t*))cat_dlsym(mod->module, "cat_module_set_pointer");
    if (!mod->set_pointer)
        return req_func_not_found("cat_module_set_pointer", path);

    /* optional exports */
    mod->unload = (void(*)())cat_dlsym(mod->module, "cat_module_unload");
    mod->name = (const char* (*)())cat_dlsym(mod->module, "cat_module_name");
    mod->description = (const char* (*)())cat_dlsym(mod->module, "cat_module_description");
    mod->author = (const char* (*)())cat_dlsym(mod->module, "cat_module_author");
    return MODULE_SUCCESS;
}

bool cat_init_module(cat_module_t* module)
{
    if (!module || !cat)
        return false;
    if (module->loaded)
        return true;

    module->loaded = module->load();
    if (!module->loaded)
        blog(LOG_WARNING, "Failed to initialize module '%s'",module->file);

    return module->loaded;
}

void cat_log_loaded_modules(void)
{
    blog(LOG_INFO, "  Loaded Modules:");

    for (cat_module_t* mod = cat->first_module; !!mod; mod = mod->next)
        blog(LOG_INFO, "    %s", mod->file);
}

/*************************模块加载****************************************/

void cat_add_module_path(const char* bin, const char* data)
{
    struct cat_module_path cmp;

    if (!cat || !bin || !data)
        return;

    cmp.bin = bstrdup(bin);
    cmp.data = bstrdup(data);
    da_push_back(cat->module_paths, &cmp);
}

static void load_all_callback(void* param, const cat_module_path* info)
{
    cat_module_t* module;

    int code = cat_open_module(&module, info->bin, info->data);
    if (code != MODULE_SUCCESS) {
        blog(LOG_DEBUG, "Failed to load module file '%s': %d",info->bin, code);
        return;
    }

    cat_init_module(module);

    UNUSED_PARAMETER(param);
}

void cat_load_all_module_from_path()
{
    if (!cat)
        return;

    for (size_t i = 0; i < cat->module_paths.num; i++) {
        cat_module_path* cmp = cat->module_paths.array + i;
        load_all_callback(NULL, cmp);
    }
}

void cat_realse_dll(void* param, cat_module_t* module) {

    cat_dlclose(module->module);

};

void cat_release_all_module()
{
    cat_enum_modules(cat_realse_dll,NULL);
}

/*******************************模块信息初始化***********************************************/

static inline bool update(Json::Value& cfg_default, Json::Value& cfg)
{
    bool is_update = true;
    for (const auto& key : cfg.getMemberNames())
        if (cfg_default.isMember(key))
        {
            if (cfg_default[key].type() != cfg[key].type())
            {
                blog(LOG_ERROR, "Value type error in config.json");
                return false;
            }
            if (cfg_default[key].isArray())
                for (Json::Value& v : cfg[key])
                    if (v.type() != cfg_default[key][0].type())
                    {
                        blog(LOG_ERROR, "Value type error in config.json");
                        return false;
                    }
            if (cfg_default[key].isObject())
                is_update &= update(cfg_default[key], cfg[key]);
            else
                cfg_default[key] = cfg[key];
        }
    return is_update;
}
static inline bool check_module_info(cat_source_type type,int index) {

    if (type== CAT_SOURCE_TYPE_MODE) {
        if (!cat->default_config->json["plugins"]["mode_ex"][index].isNull())
        {
            cat->default_config->json["plugins"]["mode_ex"].removeIndex(index, nullptr); 
            cat->buffer_config->json["plugins"]["mode_ex"].removeIndex(index, nullptr);
            return true;
        }              
    }
    else 
    {
        if (!cat->default_config->json["plugins"]["module"][index].isNull())
        {
            cat->default_config->json["plugins"]["module"].removeIndex(index, nullptr); 
            cat->buffer_config->json["plugins"]["module"].removeIndex(index, nullptr); 
            return true;
        }    
    }
    return false;
}

static inline void append_module_info_to_cfg(cat_source_t* module,int index) {  

    if (module->info->type == CAT_SOURCE_TYPE_MODE) {
        Json::Value root;
        root["module_id"] = module->info->id;
        root["module_name"] = module->info->get_name();
        root["module_data_path"] = module->info->get_default_config_name();
        root["active"] = false;
        if (cat->default_config->json["plugins"]["mode_ex"][index].isNull()) 
        {
            cat->default_config->json["plugins"]["mode_ex"][index] = root;
            cat->buffer_config->json["plugins"]["mode_ex"][index] = root;
        }
        else if (cat->default_config->json["plugins"]["mode_ex"][index]["module_id"].isNull())
        {
            cat->default_config->json["plugins"]["mode_ex"][index] = root;
            cat->buffer_config->json["plugins"]["mode_ex"][index] = root;
        }
        else if(cat->default_config->json["plugins"]["mode_ex"][index]["module_id"].asInt()!= module->info->id)
        {

            cat->default_config->json["plugins"]["mode_ex"][index] = root;
            cat->buffer_config->json["plugins"]["mode_ex"][index] = root;
        }        
    }
    else 
    {
        Json::Value root;
        root["module_id"] = module->info->id;
        root["module_name"] = module->info->get_name();
        if (module->info->get_default_config_name)
        {
            root["module_data_path"] = module->info->get_default_config_name();
        }
        else
        {
            root["module_data_path"] = "data/";
        }    
        root["active"] = true;

        if (cat->default_config->json["plugins"]["module"][index].isNull()) {

            cat->default_config->json["plugins"]["module"][index] = root;
            cat->buffer_config->json["plugins"]["module"][index] = root;
                 
        }
        else if (cat->default_config->json["plugins"]["module"][index]["module_id"].isNull())
        {
            cat->default_config->json["plugins"]["module"][index] = root;
            cat->buffer_config->json["plugins"]["module"][index] = root;
        }
        else if(cat->default_config->json["plugins"]["module"][index]["module_id"].asInt() != module->info->id)
        {
            cat->default_config->json["plugins"]["module"][index] = root;
            cat->buffer_config->json["plugins"]["module"][index] = root;
        }
      
    }
}

void cat_load_all_module_info()
{
    int mode_ex = 0;
    int module_count = 0;
    /*********************加载模块****************************/
    for (size_t i = 0; i < cat->mode_types.num; i++) {
        cat_source_info* info = &cat->mode_types.array[i];
        if(info){
            cat_source_t *module = cat_source_create_internal(info);
            module->next = cat->data.first_mode;
            module->isInit = false;
            cat->data.first_mode = module; 
            append_module_info_to_cfg(module, mode_ex);
            mode_ex++;
        }
    }
    while (check_module_info(CAT_SOURCE_TYPE_MODE, mode_ex))
        mode_ex++;
    /*********************加载输入****************************/
    for (size_t i = 0; i < cat->input_types.num; i++) {
        cat_source_info* info = &cat->input_types.array[i];
        if (info) {
            cat_source_t *module = cat_source_create_internal(info);
            module->next = cat->data.first_input;
            module->isInit = false;
            cat->data.first_input = module; 
            append_module_info_to_cfg(module, module_count);
            module_count++;
        }
    }
    /*********************加载输出****************************/
    for (size_t i = 0; i < cat->output_types.num; i++) {
            cat_source_info* info = &cat->output_types.array[i];
        if (info) {   
            cat_source_t *module =  cat_source_create_internal(info);
            module->next = cat->data.first_output;
            module->isInit = false;
            cat->data.first_output = module;
            append_module_info_to_cfg(module, module_count);
            module_count++;
        }
    }
    /*********************加载ui****************************/
    for (size_t i = 0; i < cat->ui_types.num; i++) {
        cat_source_info* info = &cat->ui_types.array[i];
        if (info) {
            cat_source_t* module = cat_source_create_internal(info);
            module->next = cat->data.first_ui;
            module->isInit = false;
            cat->data.first_ui = module;
            append_module_info_to_cfg(module, module_count);
            module_count++;
        }
    }
    while (check_module_info(CAT_SOURCE_TYPE_INPUT, module_count))
        module_count++;
}

void cat_regist_event(cat_source_info* info)
{
    if (!info)
        return;

    int id = info->id;

    cat_hook_regist_tick(info->Tick, id);
    cat_hook_regist_key_press(info->OnKeyPress,id);
    cat_hook_regist_mouse_click(info->OnMouseClick,id);
    cat_hook_regist_mouse_move(info->OnMouseMove, id);
    cat_hook_regist_force_mouse_move(info->OnForceMouseMove, id);
    cat_hook_regist_joystick_button_press(info->OnJoystickButtonPress,id);
    cat_hook_regist_joystick_axis_move(info->OnjoystickAxisMove, id);
}

void cat_fire_event(cat_source_info* info)
{

    if (!info)
        return;

    int id = info->id;

    cat_hook_fire_tick( id);
    cat_hook_fire_key_press(id);
    cat_hook_fire_mouse_click(id);
    cat_hook_fire_mouse_move(id);
    cat_hook_fire_force_mouse_move(id);
    cat_hook_fire_joystick_button_press(id);
    cat_hook_fire_joystick_axis_move(id);
}

/*************************模块遍历****************************************/

void cat_enum_modules(cat_enum_module_callback_t callback, void* param)
{
    struct cat_module* module;
    if (!cat)
        return;

    module = cat->first_module;
    while (module) {
        callback(param, module);
        module = module->next;
    }
}

void cat_enum_mode(bool(*enum_proc)(void*, cat_source_t*), void* param)
{
    cat_source_t* source;

    if (!cat)
        return;
    source = cat->data.first_mode;
    while (source) {
        cat_source_t* next_source =(cat_source_t*)source->next;

        if (!enum_proc(param, source)) {
            source = next_source;
            continue;
        }
        source = next_source;
    }
}

void cat_enum_input(bool(*enum_proc)(void*, cat_source_t*), void* param)
{
    cat_source_t* source;

    if (!cat)
        return;
    source = cat->data.first_input;
    while (source) {
        cat_source_t* next_source = (cat_source_t*)source->next;

        if (!enum_proc(param, source)) {
            source = next_source;
            continue;
        }
        source = next_source;
    }
}

void cat_enum_output(bool(*enum_proc)(void*, cat_source_t*), void* param)
{
    cat_source_t* source;

    if (!cat)
        return;
    source = cat->data.first_output;
    while (source) {
        cat_source_t* next_source = (cat_source_t*)source->next;

        if (!enum_proc(param, source)) {
            source = next_source;
            continue;
        }
        source = next_source;
    }
}

void cat_enum_ui(bool(*enum_proc)(void*, cat_source_t*), void* param)
{
    cat_source_t* source;

    if (!cat)
        return;
    source = cat->data.first_ui;
    while (source) {
        cat_source_t* next_source = (cat_source_t*)source->next;

        if (!enum_proc(param, source)) {
            source = next_source;
            continue;
        }
        source = next_source;
    }
}

/*************************注册反射****************************************/

void cat_register_source_s(const cat_source_info* info, size_t size)
{
    struct cat_source_info data = { 0 };
    struct darray* array = NULL;

    if (info->type == CAT_SOURCE_TYPE_MODE) {
        array = &cat->mode_types.da;
    }
    else if (info->type == CAT_SOURCE_TYPE_INPUT) {
        array = &cat->input_types.da;
    }
    else if (info->type == CAT_SOURCE_TYPE_OUTPUT) {
        array = &cat->output_types.da;
    }
    else if (info->type == CAT_SOURCE_TYPE_UI) {
        array = &cat->ui_types.da;
    }
    else{
        blog(LOG_WARNING,"Tried to register unknown source type: %u", info->type);
        goto error;
    }

    memcpy(&data, info, size);

    if (array)
        darray_push_back(sizeof(struct cat_source_info), array, &data);
error:
    return;
}

/*************************调用mode模块方法****************************************/
/*同一时间只能有一个mode*/
static inline bool load_mode(void* id, cat_source_t* cr) {
    
    if (cr->info->id == (int)id&&!cr->isInit&& cr->info->Init) {
        cat_data_t* cfg = cat_load_default_config();
        cr->info->Init(cfg);
        cr->isInit = true;
        cat_regist_event(cr->info);
        return true;
    }
    return false;
}

static inline bool update_mode(void* id, cat_source_t* cr) {

    if (cr->info->id == (int)id && cr->isInit && cr->info->Update) {
        cat_data_t* cfg = cat_load_default_config();
        cr->info->Update(cfg);
        return true;
    }
    return false;
}

static inline bool run_mode(void* id, cat_source_t* cr) {

    if (cr->info->id == (int)id&& cr->isInit&& cr->info->Run) {
        cr->info->Run(cat->window);
        return true;
    }
    return false;
}

static inline bool release_mode(void* id, cat_source_t* cr) {

    if (cr->info->id == (int)id && cr->isInit&& cr->info->Release) {
        cr->info->Release();
        cr->isInit = false;
        cat_fire_event(cr->info);
        return true;
    }
    return false;
}

int cat_get_curent_mode_id()
{
    if (cat) {
        return cat_data_get_mode(cat->default_config);
    }
    return 0;
}

void cat_set_curent_mode_id(int i)
{
    if(cat)
        cat->default_config->json["plugins"]["mode"] = i;
}

void cat_init_mode(int id)
{
    if (cat) {
        cat_enum_mode(load_mode, (void*)id);
    }
}

void cat_update_mode(int id)
{
    if (cat) {
        cat_enum_mode(update_mode, (void*)id);
    }
}

void cat_run_mode(int id)
{
    if (cat) {
        cat_enum_mode(run_mode, (void*)id);
    }
}

void cat_release_mode(int id)
{
    if (cat) {
        cat_enum_mode(release_mode, (void*)id);
    }
}

/*************************调用模块方法****************************************/
static inline bool check_module_active(int id) {
    for (auto entry = cat->default_config->json["plugins"]["module"].begin(); entry != cat->default_config->json["plugins"]["module"].end(); entry++)
    {
        if ((*entry).isNull())
            continue;
        if (!(*entry)["module_id"].isNull()&&(*entry)["module_id"].asInt() == id) {
            return (*entry)["active"].asBool();
        }
    }
    return false;
}

static inline bool load_module(void* id, cat_source_t* cr) {

    cat_data_t* cfg = cat_load_default_config();
    if (cfg&&!cr->isInit&& cr->info->Init) {
        cr->info->Init(cfg);
        cr->isInit = true;
        cat_regist_event(cr->info);
    }
    return true;
}

static inline bool update_module(void* id, cat_source_t* cr) {

    cat_data_t* cfg = cat_load_default_config();
    if(cfg && cr->isInit && cr->info->Update)
        cr->info->Update(cfg);
    return true;
}

static inline bool run_module(void* id, cat_source_t* cr) {
    
    if(cat->window&&cr->isInit && cr->info->Run&& check_module_active(cr->info->id))
        cr->info->Run(cat->window);
    return true;
}

static inline bool release_module(void* id, cat_source_t* cr) {
    if (cr->isInit) {
        cr->info->Release();
        cr->isInit = false;
        cat_fire_event(cr->info);
    }
    return true;
}

/*************************调用input模块方法****************************************/
void cat_init_input()
{
    if (cat) {
        cat_enum_input(load_module, NULL);
    }
}

void cat_update_input()
{
    if (cat) {
        cat_enum_input(update_module, NULL);
    }
}

void cat_run_input()
{
    if (cat) {
        cat_enum_input(run_module, NULL);
    }
}

void cat_release_input()
{
    if (cat) {
        cat_enum_input(release_module, NULL);
    }
}

/*************************调用gui模块方法****************************************/

void cat_init_ui()
{
    if (cat) {
        cat_enum_ui(load_module, NULL);
    }
}

void cat_update_ui()
{
    if (cat) {
        cat_enum_ui(update_module, NULL);
    }
}

void cat_run_ui()
{
    if (cat) {
        cat_enum_ui(run_module, NULL);
    }
}

void cat_release_ui()
{
    if (cat) {
        cat_enum_ui(release_module, NULL);
    }
}

/*************************调用output模块方法****************************************/
void cat_init_output()
{
    if (cat) {
        cat_enum_output(load_module, NULL);
    }
}

void cat_update_output()
{
    if (cat) {
        cat_enum_output(update_module, NULL);
    }
}

void cat_run_output()
{
    if (cat) {
        cat_enum_output(run_module, NULL);
    }
}

void cat_release_output()
{
    if (cat) {
        cat_enum_output(release_module, NULL);
    }
}

void cat_play_sound(const char* filename , bool isStop)
{
    cat_audio_play_sound(filename, isStop);
}


